package com.test.core;

import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.test.dao.MainDAO;
import com.test.objects.Author;
import com.test.objects.Comment;
import com.test.objects.ConfigObject;
import com.test.objects.MyPageException;
import com.test.objects.Relation;

@SuppressWarnings("deprecation")
public class MainService {
	public final String CHR_SPLIT = "!!sp_c!!";
	public final int RETCODE_OK = 200;
	public final int RETCODE_ERROR = 404;
	
	private MainDAO mainDAO;
	private ConfigObject configObject;
	private SimpleDateFormat sdf = new SimpleDateFormat(
			"EEE, MMM d, yyyy hh:mm a");
	private SimpleDateFormat sdfDob = new SimpleDateFormat(
			"dd/MM/yyyy");
	public void setMainDAO(MainDAO mainDAO){
		this.mainDAO = mainDAO;
	}
	
	public void setConfigObject(ConfigObject configObject){
		this.configObject = configObject;
	}
	
	public String getAuthorError(){
		Document doc = createDoc();
		Element root = doc.createElement("error");
		Element type = doc.createElement("type");
		type.setTextContent("unauthorized");
		root.appendChild(type);
		Element message = doc.createElement("message");
		message.setTextContent("you have no authority to access this page.");
		root.appendChild(message);
		doc.appendChild(root);
		return transformData(doc).toString();
	}
	
	public String getMostRecentCommentsInHtml(int ownerId, int authorId, int offset){
		Comment[] comments = this.mainDAO.getMostRecentComments(
						authorId, offset, this.configObject.getCommentSize());
		Document xmldoc = createDoc();
		Element root = xmldoc.createElement("data");
		
		Element rootOwner = xmldoc.createElement("owner");
		rootOwner.setAttribute("id", Integer.toString(ownerId));
		Author autOwner = this.mainDAO.getAuthor(ownerId);
		
		rootOwner.setAttribute("o_fstName", autOwner.getFirstname());
		rootOwner.setAttribute("o_fname", autOwner.getFullname());
		rootOwner.setAttribute("o_acc", autOwner.getAccount());
		rootOwner.setAttribute("o_dob", sdfDob.format(autOwner.getDob()));
		rootOwner.setAttribute("o_addr", autOwner.getAddress());
		rootOwner.setAttribute("o_img", autOwner.getImageUrl());
		rootOwner.setAttribute("o_desc", autOwner.getDescription());
		root.appendChild(rootOwner);
		
		Element rootAuthor = xmldoc.createElement("author");
		rootAuthor.setAttribute("id", Integer.toString(authorId));
		Author aut = this.mainDAO.getAuthor(authorId);
		
		rootAuthor.setAttribute("a_fstName", aut.getFirstname());
		rootAuthor.setAttribute("a_fname", aut.getFullname());
		rootAuthor.setAttribute("a_acc", aut.getAccount());
		rootAuthor.setAttribute("a_dob", sdfDob.format(aut.getDob()));
		rootAuthor.setAttribute("a_addr", aut.getAddress());
		rootAuthor.setAttribute("a_img", aut.getImageUrl());
		rootAuthor.setAttribute("a_desc", aut.getDescription());
		root.appendChild(rootAuthor);
		
		Element rootCfg = xmldoc.createElement("config");
		rootCfg.setAttribute("c_paging", 
				Integer.toString(this.configObject.getCommentSize()));
		rootCfg.setAttribute("rel_size", 
				Integer.toString(this.configObject.getRelationSize()));
		rootCfg.setAttribute("p_paging", 
				Integer.toString(this.configObject.getPostPaging()));
		root.appendChild(rootCfg);
		
		Element rootCmt = xmldoc.createElement("comments");
		Element e;
		for (int i = 0; i < comments.length; i++){
			e = cmt2elmt(comments[i], xmldoc);
			rootCmt.appendChild(e);
		}
		root.appendChild(rootCmt);
		xmldoc.appendChild(root);
		String outData = transformData(xmldoc);
		return outData;
	}
	
	public String saveMainComment(String data){
		data = data.replace("{", "").replace("}", "");
		String[] elements = data.split(CHR_SPLIT);
		Comment c = new Comment();
		c.setParentId(0);
		Author aut = new Author();
		aut.setId(Integer.parseInt(elements[0]));
		c.setAuthor(aut);
		c.setContent(elements[3]);
		c.setUrl(elements[4]);
		c.setContentEx(elements[5]);
		c.setDateTime(new Date(elements[6]));
		
		Document doc = createDoc();
		Element root = doc.createElement("result");
		Element code = doc.createElement("return-code");
		Element eData = doc.createElement("data");
		try {
			int newId = this.mainDAO.saveComment(c);
			String newData = newId + CHR_SPLIT + data; 
			code.setTextContent(Integer.toString(RETCODE_OK));
			eData.setTextContent(newData);
			root.appendChild(code);
			root.appendChild(eData);
		}catch(MyPageException ex){
			code.setTextContent(Integer.toString(RETCODE_ERROR));
			eData.setTextContent(
					ex.getClass().toString() + ": " + 
					ex.getMessage());
			root.appendChild(code);
			root.appendChild(eData);
		}
		doc.appendChild(root);
		String outData = transformData(doc);
		return outData;
	}
	
	public String saveComment(String data){
		data = data.replace("{", "").replace("}", "");
		String[] elements = data.split(CHR_SPLIT);
		Comment c = new Comment();
		c.setParentId(Integer.parseInt(elements[0]));
		Author aut = new Author();
		aut.setId(Integer.parseInt(elements[1]));
		c.setAuthor(aut);
		c.setContent(elements[4]);
		c.setUrl("");
		c.setContentEx("");
		c.setDateTime(new Date(elements[7]));
		
		Document doc = createDoc();
		Element root = doc.createElement("result");
		Element code = doc.createElement("return-code");
		Element eData = doc.createElement("data");
		try {
			int newId = this.mainDAO.saveComment(c);
			String newData = newId + CHR_SPLIT + data; 
			code.setTextContent(Integer.toString(RETCODE_OK));
			eData.setTextContent(newData);
			root.appendChild(code);
			root.appendChild(eData);
		}catch(MyPageException ex){
			code.setTextContent(Integer.toString(RETCODE_ERROR));
			eData.setTextContent(
					ex.getClass().toString() + ": " + 
					ex.getMessage());
			root.appendChild(code);
			root.appendChild(eData);
		}
		doc.appendChild(root);
		String outData = transformData(doc);
		return outData;
	}
	
	public String getLimitRelation(int authorId){
		Relation[] rels = this.mainDAO.getRelation(
				authorId, 0, this.configObject.getRelationSize());
		Author aut = this.mainDAO.getAuthor(authorId);
		Document doc = createDoc();
		Element root = doc.createElement("relations");
		root.setAttribute("a_id", Integer.toString(authorId));
		root.setAttribute("a_fstName", aut.getFirstname());
		root.setAttribute("a_fname", aut.getFullname());
		root.setAttribute("a_img", aut.getImageUrl());
		Element eRel;
		Relation r;
		for (int i = 0; i < rels.length; i++){
			r = rels[i];
			eRel = doc.createElement("relation");
			eRel.setAttribute("id", Integer.toString(r.getId()));
			eRel.setAttribute("f_id", 
				Integer.toString(r.getAuthor().getId()));
			eRel.setAttribute("f_fname", r.getAuthor().getFullname());
			eRel.setAttribute("f_img", r.getAuthor().getImageUrl());
			eRel.setAttribute("f_startDate", 
					sdf.format(r.getRelationStartDate()));
			eRel.setAttribute("f_type", Integer.toString(r.getType()));
			eRel.setAttribute("f_desc", r.getDesc());
			root.appendChild(eRel);
		}
		doc.appendChild(root);
		String outData = transformData(doc);
		return outData;
	}
	
	public String removeComment(int id){
		Document doc = createDoc();
		Element root = doc.createElement("result");
		Element code = doc.createElement("return-code");
		Element eData = doc.createElement("data");

		try {
			boolean delRes = this.mainDAO.deleteComment(id);
			code.setTextContent(delRes ? 
					Integer.toString(RETCODE_OK) : 
					Integer.toString(RETCODE_ERROR));
			if (!delRes)
				eData.setTextContent("unknown error");
		}catch(MyPageException mpEx){
			code.setTextContent(Integer.toString(RETCODE_ERROR));
			eData.setTextContent(
					mpEx.getClass().toString() + ": " +
					mpEx.getMessage());
		}
			
		root.appendChild(code);
		root.appendChild(eData);
		doc.appendChild(root);
		
		String outData = transformData(doc);
		return outData;
	}
	
	private Document createDoc(){
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			return db.newDocument();
		}catch(Exception ex){
			System.err.println("[mypage-main] [mainservice-createDoc] " + 
					ex.getClass().toString() + ": " + ex.getMessage());
			return null;
		}
	}
	
	private String transformData(Document doc){
		try {
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			StringWriter writer = new StringWriter();
			Result result = new StreamResult(writer);
			DOMSource source = new DOMSource(doc);
			transformer.transform(source, result);
			return writer.toString();
		}catch(Exception ex){
			System.err.println("[mypage-main] [mainservice-transformData] " + 
					ex.getClass().toString() + ": " + ex.getMessage());
			return "";
		}
	}
	
	private Element cmt2elmt(Comment c, Document doc){
		
		Element e = doc.createElement("comment");
		e.setAttribute("id", Integer.toString(c.getId()));
		e.setAttribute("parentId", Integer.toString(c.getParentId()));
		e.setAttribute("authorId", Integer.toString(c.getAuthor().getId()));
		e.setAttribute("a_fname", c.getAuthor().getFullname());
		e.setAttribute("a_img", c.getAuthor().getImageUrl());
		e.setAttribute("content", c.getContent());
		e.setAttribute("url", c.getUrl());
		e.setAttribute("contentEx", c.getContentEx());
		e.setAttribute("postDate", sdf.format(c.getDateTime()));
		Comment[] subs = c.getSubComments();
		if (subs.length > 0){
			Element s;
			Comment sc;
			for (int i = 0; i < subs.length; i++){
				sc = subs[i];
				s = doc.createElement("sub-comment");
				s.setAttribute("id", Integer.toString(sc.getId()));
				s.setAttribute("parentId", Integer.toString(sc.getParentId()));
				s.setAttribute("authorId", Integer.toString(sc.getAuthor().getId()));
				s.setAttribute("a_fname", sc.getAuthor().getFullname());
				s.setAttribute("a_img", sc.getAuthor().getImageUrl());
				s.setAttribute("content", sc.getContent());
				s.setAttribute("url", sc.getUrl());
				s.setAttribute("contentEx", sc.getContentEx());
				s.setAttribute("postDate", sdf.format(sc.getDateTime()));
				e.appendChild(s);
			}
		}
		return e;
	}
}
